package init.luoyu.easymonitor.zabbix.server;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import init.luoyu.easymonitor.base.model.ServiceResult;
import init.luoyu.easymonitor.base.utils.CommonUtil;
import init.luoyu.easymonitor.zabbix.enums.ZabbixMethod;
import init.luoyu.easymonitor.zabbix.model.History;
import init.luoyu.easymonitor.zabbix.model.Host;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author LuoYu
 * date 2021/4/23
 */
public class ZabbixServer {


    private static final Logger logger = LoggerFactory.getLogger(ZabbixServer.class);

    /**
     * 请求地址
     */
    public static   String url;

    /**
     * 请求密钥
     */
    private static   String auth;

    /**
     * 用户名称
     */
    public static String username;

    /**
     * 密码
     */
    public static String password;


    /**
     * <p>创建主机</p>
     * @param host  主机
     * @return
     */
    public static ZabbixResponse createHost(Host host){
        logger.info("创建监控主机 ----> 主机名称:{}",host.getHost());
       return executeOut(host, ZabbixMethod.CREATE_HOST);
    }


    /**
     * <p>删除实体</p>
     * @param ids  id集合
     * @param method   删除方法{@link ZabbixMethod}
     * @return
     */
    public static ZabbixResponse delete(List<String> ids,ZabbixMethod method){
        if(CommonUtil.isEmptyCollection(ids)){
            throw new RuntimeException("id不能为空");
        }
        Executor executor = new Executor();
        return executor.responseMap(ids,method);
    }

    /**
     * <p>获取主机接口</p>
     * @param hostId  主机id
     * @return        接口列表
     */
    public static JSONArray getHostInterface(Integer hostId) {
        Map<String,Object> map = new HashMap<>();
        map.put("hostids",hostId);
        map.put("output", "extend");
        Executor executor = new Executor();
        return executor.responseArray(map, ZabbixMethod.HOST_INTERFACE_GET);
    }


    /**
     * <p>获取监控项监控数据</p>
     * @param ids  监控项id集合
     * @return     数据列表
     */
    public static JSONArray getMonitorDataByItemIds(List<String> ids) {
        if(CommonUtil.isEmptyCollection(ids)) {
            logger.warn("监控项id不能为空....");
            return null;
        }
        History history = new History();
        history.setItemids(ids);
        history.setLimit(ids.size());
        return new Executor().responseArray(history,ZabbixMethod.HISTORY_GET);
    }




    /**
     * <p>更新实体</p>
     * @param params    参数
     * @param method    更新方法
     * @return
     */
    public static ZabbixResponse update(Map<String,Object> params,ZabbixMethod method){
        if(CommonUtil.isEmptyMap(params)){
            throw new RuntimeException("参数不能为空");
        }
        Executor executor = new Executor();
        return executor.responseMap(params,method);
    }


    /**
     * <p>获取实体</p>
     * @param params  参数
     * @param method    方法
     * @return
     */
    public static ZabbixResponse getMap(Map<String,Object> params,ZabbixMethod method){
        if(CommonUtil.isEmptyMap(params)){
            throw new RuntimeException("id不能为空");
        }
        Executor executor = new Executor();
        return executor.responseMap(params,method);
    }


    public static ZabbixResponse executeOut(ZabbixRequest request, ZabbixMethod method){
        Executor executor = new Executor();
        ServiceResult<Boolean> serviceResult = request.paramsChecker();
        if(!serviceResult.isSuccess()) {
            return ZabbixResponse.error(serviceResult.getMessage());
        }
        return executor.responseMap(request,method);
    }












    private static class Executor{
        private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        private  OkHttpClient okHttpClient = new OkHttpClient();
        /**
         * 登录
         */
        public void login(){
            Map<String,Object> requestBody = Maps.newHashMap();
            requestBody.put("id",1);
            requestBody.put("jsonrpc","2.0");
            requestBody.put("method",ZabbixMethod.USER_LOGIN.getMethod());
            Map<String,String> userMap = new HashMap<>(2);
            userMap.put("user",username);
            userMap.put("password",password);
            requestBody.put("params",userMap);
            RequestBody body = RequestBody.create(JSON,JSONObject.toJSONString(requestBody));
            final Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
            final Call call = okHttpClient.newCall(request);
            Response execute;
            try {
                execute = call.execute();
                if(execute.body() != null){
                    auth =  JSONObject.parseObject(execute.body().string()).getString("result");
                }
                logger.info("远程登录zabbix主机获取令牌 ----> 令牌:{}",auth);
            } catch (IOException e) {
                logger.error("登录zabbix主机时发生错误 ----> Error:{}",e.getMessage());
                e.printStackTrace();
            }
        }



        /**
         * 执行方法
         * @return   处理响应信息
         */
        public ZabbixResponse responseMap(Object params,ZabbixMethod method){
            try {
                JSONObject jsonObject = execute(params, method);
                if(jsonObject == null) {
                    return ZabbixResponse.error("未请求到数据");
                }
                JSONObject result = jsonObject.getJSONObject("result");
                Map<String,String> map = new HashMap<>();
                Set<String> keySet = result.keySet();
                keySet.forEach(k-> map.put(k,result.getString(k)));
                return ZabbixResponse.success(map);
            }catch (IOException e) {
                logger.error("请求Zabbix主机时发生错误 ---->Error:{}",e.getMessage());
                return ZabbixResponse.error(e.getMessage());
            }
        }


        public JSONArray responseArray(Object params,ZabbixMethod method) {
            try {
                JSONObject jsonObject = execute(params, method);
                if(jsonObject == null) {
                    return null;
                }
                return jsonObject.getJSONArray("result");
            }catch (IOException e) {
                logger.error("请求Zabbix主机时发生错误 ---->Error:{}",e.getMessage());
                return null;
            }
        }




        public JSONObject execute(Object params,ZabbixMethod method) throws IOException {
            logger.info("请求Zabbix主机 ----> 请求方法:{}",method.getMethod());
            login();
            String jsonString = JSONObject.toJSONString(getMap(params, method));
            logger.debug(jsonString);
            RequestBody body = RequestBody.create(JSON,jsonString);
            final Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
            final Call call = okHttpClient.newCall(request);
            Response execute;
                execute = call.execute();
                if(execute.body() == null){
                    return null;
                }
                JSONObject parseObject = JSONObject.parseObject(execute.body().string());
                if (parseObject.containsKey("error")) {
                    JSONObject error = parseObject.getJSONObject("error");
                    String msg = String.format("code:%s -- data:%s -- message:%s",error.getString("code"),error.getString("data"),error.getString("message"));
                    throw new RuntimeException(msg);
                }
                return parseObject;
        }







        /**
         *  生成参数
         */
        private Map<String,Object> getMap(Object params,ZabbixMethod method){
            Map<String,Object> map = new HashMap<>();
            map.put("jsonrpc","2.0");
            map.put("id",1);
            map.put("method",method.getMethod());
            map.put("params",params);
            map.put("auth", ZabbixServer.auth);
            return map;
        }

    }
































}
